package cn.bon.websocket.handler;


import cn.bon.common.adapter.JsonSerializerAdapter;
import cn.bon.common.tool.RedisUtils;
import cn.bon.common.utils.JwtUtils;
import cn.bon.websocket.enums.MessageType;
import cn.bon.websocket.pojo.bo.WebsocketUserBO;
import cn.bon.websocket.pojo.dto.MessageDTO;
import cn.bon.websocket.pojo.dto.WebsocketMessage;
import cn.bon.websocket.pool.UserPool;
import cn.bon.websocket.pool.WaitingAuthenticationUserPool;
import cn.bon.websocket.pusher.DefaultChannelPusher;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.jsonwebtoken.Claims;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author: dronff
 * @description:
 * @CreateTime: 2023/12/11 8:59
 **/
@Slf4j
@Data
@Component
public class WebsocketCoreHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private final JwtUtils jwtUtils;
    private UserPool userPool;


    private JsonSerializerAdapter jsonSerializerAdapter;
    public WebsocketCoreHandler(UserPool userPool, JsonSerializerAdapter jsonSerializerAdapter, JwtUtils jwtUtils){
        this.userPool = userPool;
        this.jwtUtils = jwtUtils;
        this.jsonSerializerAdapter = jsonSerializerAdapter;
    }
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws JsonProcessingException {
        MessageDTO message = null;
        try {
            message = jsonSerializerAdapter
                    .readJsonAsObject(textWebSocketFrame.text(), MessageDTO.class);
        } catch (JsonProcessingException ignored) {
        }
        if (message != null) {
            if (message.getMessageType() == MessageType.CONNECTION_AUTHENTICATE) {
                WebsocketMessage data = message.getData();
                String tk = (String) data.getData();
                if (tk != null && !tk.trim().isEmpty()) {
                    Claims claims = jwtUtils.getClaimsFromToken(tk);
                    if (claims == null) {
                        // 非法token
                        channelHandlerContext.channel().close();
                        new DefaultChannelPusher(channelHandlerContext.channel(), jsonSerializerAdapter).push(
                                MessageDTO.builder()
                                        .messageType(MessageType.CONNECTION_FAIL)
                                        .build()
                        );
                        return;
                    }
                    Map map = (Map) RedisUtils.get("user:login:" + claims.get("username").toString());
                    if (map == null || map.get("token") == null || !tk.equals(map.get("token")) || claims.getExpiration().before(new Date())) {
                        // 该token不存在于redis或已过期
                        // token过期 响应头中添加清除token
                        channelHandlerContext.channel().close();
                        new DefaultChannelPusher(channelHandlerContext.channel(),jsonSerializerAdapter).push(
                                MessageDTO.builder()
                                        .messageType(MessageType.CONNECTION_FAIL)
                                        .build()
                        );
                        return;
                    }
                    String username = claims.get("username", String.class);
                    List auths = (List)((Map)map.get("authentication")).get("authorities");
                    List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
                    grantedAuthorities.add(new SimpleGrantedAuthority("simple"));
                    if (userPool.get(username) != null) {
                        userPool.get(username).shutDown();
                    }
                    WebsocketUserBO ub = WebsocketUserBO
                            .builder()
                            .username(username)
                            .token(tk)
                            .pusher(
                                    new DefaultChannelPusher(channelHandlerContext.channel(),jsonSerializerAdapter)
                            )
                            .grantedAuthorities(grantedAuthorities)
                            .build();
                    userPool.put(
                            username,
                            ub
                    );
                    ub.push(
                            MessageDTO.builder()
                                    .messageType(MessageType.CONNECTION_SUCCESS)
                                    .build()
                    );
                }else{
                    channelHandlerContext.channel().close();
                }
            }
        }
    }
}
